/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

#include <基本类型.h>

#include <list>
#include <set>

#include "引擎枚举数据.h"
#include "引擎数据类型.h"
#include "core/设备内存缓存.h"
#include "底层绘图/底层绘图框架.h"


//using namespace std;


typedef struct {
	vec4	speed;
	float32	密度;
}S_FLIP可视数据;

typedef struct {
	vec4	loc_speed;
}S_PBF可视数据;







struct S_Object {
	E_物体类型		m_Type;
	uint32			m_ID;
	uint32			m_globalID;

	//				拾取 
	uint32			m_状态;
	std::u16string	m_Name;

	void*					m_UserData;
	S_Object*				m_父对象;
	std::vector<S_Object*>	m_子物体;

	std::atomic<int32>		m_引用计数;

	float32	m_层数量;
	int32	m_层深度;
	bool	m_是否展开;

	bool		m_可拾取;
	bool		m_显示;
	bool		m_选中;

	static C_Key分配器 m_ID生成器;

	
	S_Object(E_物体类型 type, uint32 key=0);
	~S_Object();


	virtual S_Object* f_get(uint32 key) { return 0; }
	virtual void f_选择(bool 选择) { m_选中 = 选择; }

};


typedef void(*fun_物体async_p)(S_Object* obj);

Inline S_Object* f_ob_erase(S_Object* ob, uint32 loc) {
	S_Object* emOb = nullptr;
	if (loc < ob->m_子物体.size()) {
		emOb = ob->m_子物体[loc];
		ob->m_子物体.erase(ob->m_子物体.begin() + loc);
	}
	return emOb;
}
Inline S_Object* f_ob_erase(S_Object* ob, S_Object* s) {
	S_Object* emOb = nullptr;
	for (auto it = ob->m_子物体.begin(); it != ob->m_子物体.end(); ++it) if (*it == s) {
		emOb = (*it);
		ob->m_子物体.erase(it);
		break;
	}
	return emOb;
}
Inline void f_ob_insert(S_Object* ob, S_Object* s, uint32 loc) {
	if (s->m_父对象) {
		f_ob_erase(s->m_父对象, s);
	}

	if(loc > ob->m_子物体.size()) ob->m_子物体.push_back(s);
	else ob->m_子物体.insert(ob->m_子物体.begin() + loc, s);
	s->m_父对象 = ob;
}
Inline void f_ob_clear(S_Object* ob) {
	ob->m_子物体.clear();
}

Inline void f_ob_push_back(S_Object* ob, S_Object* s) {
	ob->m_子物体.push_back(s);
	s->m_父对象 = ob;
}




typedef struct {
	float32	m_重量;
	float32 m_密度;
	
	float32 m_弹性;
	float32 m_阻尼;
	float32 m_边缘距离;
	vec3 m_摩擦;
	vec3 m_旋转惯性;

	
	vec2 m_接触参考;	//法向力和切向力
	vec2 m_接触实施;	//法向力的刚度和阻尼
	float32 m_接触混合;	//计算最终接触参数（solref 和 solimp）的混合比例

	uint32 m_碰撞位掩码;
	uint32 m_接触的频率;
	uint32 m_接触自由度;
}S_物理体材质;



typedef struct {
	vec3			大小;
	
	void*	m_Data;
}S_物理几何_方体;

typedef struct {
	vec3			大小;
	
	void* m_Data;
}S_物理几何_圆柱;

typedef struct {
	vec2			大小;

	void* m_Data;
}S_物理几何_胶囊;

typedef struct {
	float			大小;

	void* m_Data;
}S_物理几何_球体;

typedef struct {
	vec3			方向;
	vec3			位置;

	void* m_Data;
}S_物理几何_平面;

typedef struct {
	S_VNT1*	顶点;
	uint32*	索引;
	uint32	顶点数量;
	uint32	索引数量;

	vec3			方向;

	void*	m_Data;
}S_物理几何_网格;


struct S_物理几何体 : public S_Object {
	E_物理几何体类型	m_Type;
	void*				m_Data;
	S_物理体材质		g_材质;

	E_物理引擎			m_物理引擎枚举;
	S_Object*			m_绑定内置物体;
	S_Object*			m_绑定网格物体;

	std::string			m_XML;

	static C_StrKey分配器 g_名称生成器;

	S_物理几何体(E_物理几何体类型 type, std::u16string name = u"phyGeom") : S_Object(E_物体类型::t_物理几何虚拟体){
		m_绑定内置物体		= nullptr;
		m_绑定网格物体	= nullptr;
		m_Type			= type;
		m_Data			= nullptr;

		m_Name = g_名称生成器.f_Gen(name);

		g_材质.m_重量 = 1.0;
		g_材质.m_密度 = 0.0;
		g_材质.m_弹性 = 0.0;
		g_材质.m_阻尼 = 0.0;
		g_材质.m_摩擦 = {0,0,0};
		g_材质.m_旋转惯性 = { 0,0,0 };
		g_材质.m_边缘距离 = 0.0001;

		g_材质.m_接触参考 = { 0.02, 1.0 };
		g_材质.m_接触实施 = { 0.9, 0.8 };
		g_材质.m_接触混合 = 1.0;

		g_材质.m_碰撞位掩码 = 1;
		g_材质.m_接触的频率 = 1;
		g_材质.m_接触自由度 = 1;

	}
	~S_物理几何体() {
		g_名称生成器.f_Move(m_Name);
	}

	virtual void* f_get几何体物理对象() { return nullptr; };
	virtual void	f_set几何体物理数据(void* data) {};
	virtual void	f_set质量(float32 v) {};
	virtual bool	f_is空() { return true; };
};


struct S_物理体 : public S_Object {
	E_物理引擎			m_物理引擎枚举;
	E_物理体类型		m_物理体类型;
	S_物理几何体*		m_几何体;
	
	uvec2 m_粒子偏移和数量;
	//uvec2 m_速度块区;
	//uvec2 m_质量块区;

	void*				m_Data;
	uint64				m_全局偏移;
	float32				m_密度;
	S_Tranform			m_变换;


	E_物理体链接类型	m_链接类型;
	vec3				m_链接轴向;
	vec3				m_链接坐标偏移;
	
	bool		m_限定范围;
	vec2		m_关节范围;
	float32		m_关节阻尼;
	float32		m_关节刚度;
	float32		m_关节摩擦;


	S_Object*				m_绑定物体;
	S_Object*				m_虚拟链接轴绑定物体;
	std::string				m_XML;
	Mat44f					m_Matrix;
	bool					m_构建更新;

	std::vector<S_物理体*>	m_链接子物体;


	fun_物体async_p		mf_销毁;


	static C_StrKey分配器 g_名称生成器;

	S_物理体(S_物理几何体* geom, uint32 key = 0, std::u16string name = u"phyBody");
	~S_物理体();

	//void				f_绑定user到物理体上(void* data);
	static S_物理体*	f_get(uint32 key);

	virtual void*		f_getBody() { return 0; }
	virtual void*		f_get关联对象() { return 0; }

	virtual void		f_绑定关联对象(void* data) { ; }
	virtual void		f_绑定关联对象(void* data, uint32 id) { ; }
	virtual void		f_冻结(bool no) {}

	virtual void		f_setLocRot(const vec3& l, const vec3& r) {}
	virtual void		f_setPos(const vec3& l) { m_变换.position = l; }
	virtual void		f_setRot(const vec3& r) { m_变换.rotation = r; }
	virtual void		f_setVel(const vec3& l) { m_变换.position = l; }
	virtual void		f_setScl(const vec3& s) { m_变换.scale = s; }




	virtual vec3		f_getLoc() { return m_变换.position; }
	virtual vec3		f_getRot() { return m_变换.rotation; }
	virtual vec3		f_getVel() { return m_变换.rotation; }
	virtual vec3		f_getRotVel() { return { 0,0,0 }; }
	virtual vec3		f_getScl() { return m_变换.scale; }

	virtual void		f_施加力(const vec3& 力) {}
	void f_set绑定物体矩阵(const Mat44f& mat);

};

//typedef struct S_骨骼;


typedef struct {
	struct S_物体* m_始端;
	struct S_物体* m_末端;

	struct S_物体* m_末端坐标;
	//vec3*			m_末端坐标;
	int32	m_深度;
	int32	m_骨骼段数;
	uint32	m_迭代次数;

	uint32	m_IK类型;
	bool	m_使用骨节坐标;
	
}S_骨骼IK;



typedef struct {
	//uint32	m_Type;
	vec4	m_旋转;
	vec4	m_动态旋转;
	//vec3	m_欧拉旋转;
	vec3	m_初始头坐标;
	vec3	m_方向;
	float32	m_长度;

	//S_板载缓存*	m_矩阵;
	S_物体* m_骨节A;
	S_物体* m_骨节B;

	S_物体* m_根骨骼;


	S_物体* m_封套范围线;

	S_骨骼IK*	m_IK;
	int32		m_IK关联数量;
	vec3		m_变换后根坐标;
	vec3		m_变换后尾坐标;
	//vec3	m_变换坐标;
	//S_骨架* m_骨架;

	S_物体*		m_对称物体;
	vec3		m_对称偏移;
	int32		m_对称方向;


	float32		m_封套S内半径;
	float32		m_封套E内半径;

	float32		m_封套S外半径;
	float32		m_封套E外半径;

	bool		m_自动封套大小;

}S_骨骼;

CORE_ARRAY_HANDLE(S_骨骼数组, S_骨骼*)



typedef struct {
	int32		m_父骨骼ID;
	S_I32Array*	m_子骨骼;
	//S_骨骼* m_父骨骼;
	//S_骨骼数组* m_子骨骼;
}S_骨骼邻接;

CORE_ARRAY_HANDLE(S_骨骼邻接数组, S_骨骼邻接*)




typedef struct {
	//uint32	m_Type;
	S_GPU内存块 m_姿态;

	S_骨骼邻接数组*	m_骨骼邻接;
	//S_GPU内存块索引 m_骨骼属性;
	//S_GPU内存块索引 m_骨骼长度;

	//S_GPU内存块索引 m_初始姿态;
	//S_GPU内存块索引 m_变换姿态;

	//S_GPU内存块索引 m_骨骼变换;
	//S_板载缓存*	m_蒙皮权重;
	//S_板载缓存* m_顶点对应骨骼ID;
	//S_Tranform*	m_变换;
	S_物体*			m_骨头物体;

	S_骨骼IK**		m_IK;
	uint32			m_IK数量;

	//uint32			m_ID;
	uint32			m_骨头数量;
	uint32			m_骨节数量;

	bool			m_解算约束;
}S_骨架;






EngineAPI_EXPORT E_物体类型 f_ob_以名称取类型(std::wstring name);
EngineAPI_EXPORT E_物体类型 f_ob_以名称索引取类型(uint32 index);

EngineAPI_EXPORT S_Object* f_ob_查找父对象(S_Object* ob, E_物体类型 type);


//typedef bool(*fp_树形框项回调)(const struct S_树形框项& item);
//struct S_树形框项 : public S_Object {
//
//	S_树形框项() : m_是否展开(false) {};
//
//	vec2 m_线坐标;
//	//void* m_UserData;
//	bool m_是否展开;
//
//	std::vector<S_树形框项*> m_子项;
//};





